/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.esgi.dns;

import java.nio.ByteBuffer;
import org.esgi.dns.Message.DomainNameLengthException;
import org.esgi.dns.Message.LabelLengthException;

/**
 * This class is used to create the Message Question section.
 * 
 * http://www.ietf.org/rfc/rfc1035.txt
 * (§4.1.2. Question section format)
 * 
 * The question section is used to carry the "question" in most queries,
 * i.e., the parameters that define what is being asked.  The section
 * contains QDCOUNT (usually 1) entries, each of the following format:
 * 
 *                                   1  1  1  1  1  1
 *     0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
 *   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 *   |                                               |
 *   /                     QNAME                     /
 *   /                                               /
 *   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 *   |                     QTYPE                     |
 *   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 *   |                     QCLASS                    |
 *   +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
 * 
 * @author Alain Janin-Manificat <alain.janinm@hotmail.fr>
 * 
 * @see Message
 */
public class Question {

    /**
     * A domain name represented as a sequence of labels, where
     * each label consists of a length octet followed by that
     * number of octets.  The domain name terminates with the
     * zero length octet for the null label of the root.  Note
     * that this field may be an odd number of octets; no
     * padding is used.
     */
    String qName;
    
    /**
     * A a two octet code which specifies the type of the query.
     * The values for this field include all codes valid for a
     * TYPE field, together with some more general codes which
     * can match more than one type of RR.
     */
    short qType;
    
    /**
     * A two octet code that specifies the class of the query.
     * For example, the QCLASS field is IN for the Internet.
     */
    short qClass;

    
    /**
     * Getter / Setter for Question fields.
     */
    public short getqClass() {
        return qClass;
    }

    public void setqClass(short qClass) {
        this.qClass = qClass;
    }

    public String getqName() {
        return qName;
    }

    public void setqName(String qName) {
        this.qName = qName;
    }

    public short getqType() {
        return qType;
    }

    public void setqType(short qType) {
        this.qType = qType;
    }

    public ByteBuffer encode(ByteBuffer b) throws LabelLengthException, DomainNameLengthException {
        return serialize(this, b);
    }

    /**
     * Serialize the Question informations in a ByteBuffer,
     * according to the rules defined in :
     * 
     * http://www.ietf.org/rfc/rfc1035.txt
     * (§4.1.2. Question section format)
     * 
     * @param q         Question
     * @param message   ByteBuffer - The ByteBuffer use to build the Message.
     * @return          ByteBuffer - The reference to the ByteBuffer given in parameter.
     * @throws org.esgi.dns.Message.LabelLengthException
     * @throws org.esgi.dns.Message.DomainNameLengthException 
     */
    public static ByteBuffer serialize(Question q, ByteBuffer message) throws LabelLengthException, DomainNameLengthException {

        String qName = q.getqName();
        /*
         * Check if a pointer to given domain name exists. If true the pointer exists
         * and has been set.
         */
        if (!Message.setPointer(qName, message)) {
            Message.setDomainName(qName, message);
        }
        message.putShort(q.getqType());
        message.putShort(q.getqClass());

        return message;
    }

    /**
     * Unserialize a ByteBuffer containing Question informations
     * stored following the format defined in :
     * 
     * http://www.ietf.org/rfc/rfc1035.txt
     * (§4.1.2. Question section format)
     * 
     * Create an instance of Question from those informations.
     * @param input     ByteBuffer - Contains the header informations.
     * @return          Question - The Question object created from the ByteBuffer informations.
     */
    public static Question unserialize(ByteBuffer input) {
        Question q = new Question();
        
        /**
         * Allocate a ByteBuffer for QNAME with a size equals to :
         * Message position - size of QTYPE - size of QCLASS - size of Header
         */
        ByteBuffer qName = ByteBuffer.allocate(input.capacity() - 4 - Header.HEADER_SIZE); 
        for (int i = Header.HEADER_SIZE; i < input.position() - 4; i++) {
            qName.put(input.get(i));
        }
        //Get the size of QNAME.
        int qNameLength = qName.position();
        //Reset the pointer to first byte.
        qName.clear();
        String part = "", separator = "";
        
        //Iterate over the ByteBuffer.
        while (qName.position() < qNameLength) {
            //Read first byte.
            byte b = qName.get();
            //Check if it's a pointer
            if ((0xC0 & b) >> 6 == 3) {   //3 -> 11 in binary
                
                //Get the offset of the label in the Message.
                int offset = ((0x3FFF & qName.getShort(qName.position()-1)));
                
                //Position the Message buffer at given offset.
                input.position(offset);
                
                //Read the length of the label
                byte len = input.get();
                int length = (0x3F & len);
                
                //Build the label.
                part += separator;
                for (int j = 0; j < length; j++) {
                    part += (char) input.get();
                }
                //Read the second byte (a pointer is 2 bytes); 
                qName.get();
            } 
            else {
                //Get the length of the label
                int length = (0x3F & b);
                if (length == 0) {
                    break;
                }
                //Build the label.
                part += separator;
                for (int j = 0; j < length; j++) {
                    part += (char) qName.get();
                }
            }
            separator = ".";

        }
        q.setqName(part);
        input.position(12+qNameLength);
        q.setqType(input.getShort());
        q.setqClass(input.getShort());
        return q;
    }
}
